package MULE.Model;

import java.util.ArrayList;

/**
 * This class defines the logic for a game of M.U.L.E.
 * 
 * It contains all the objects needed for a game, and handles all of the logic
 * that actually runs the game.
 * 
 * @ author Anastasiya Cotton @ version 1.0 10.04.2013
 * 
 */
public class Game implements java.io.Serializable {

	/**
	 * Serial version ID.
	 */
	private static final long serialVersionUID = 5333286074628672801L;

	public final static int MIN_NUM_PLAYERS = 2;
	public final static int MAX_NUM_PLAYERS = 4;

	private Map map;
	private Difficulty difficulty;
	private int numRounds;
	private int numPlayers;
	private ArrayList<Player> players;

	/**
	 * Enumeration of game difficulties.
	 */
	public enum Difficulty {
		BEGINNER("Beginner", 6, new Inventory(0, 8, 4, 0, 0)), STANDARD(
				"Standard", 12, new Inventory(0, 4, 2, 0, 0)), TOURNAMENT(
				"Tournament", 12, new Inventory(0, 4, 2, 0, 0));

		private final String name;
		private final int numRounds;
		private final Inventory startingAmount;

		private Difficulty(String name, int numRounds, Inventory startAmount) {
			this.name = name;
			this.numRounds = numRounds;
			this.startingAmount = startAmount;
		}

		public Inventory getStartingAmount() {
			return this.startingAmount;
		}
	}

	/**
	 * Creates a new game of M.U.L.E. based off of the number of players and
	 * difficulty
	 * 
	 * @param numPlayers
	 * @param difficulty
	 */
	public Game(int numPlayers, Game.Difficulty difficulty, Map map) {
		this.numPlayers = numPlayers;
		this.difficulty = difficulty;
		this.numRounds = difficulty.numRounds;
		this.players = new ArrayList<Player>();
		this.map = map;
	}

	/**
	 * Returns the game difficulty corresponding to the given string.
	 * 
	 * @param diffStr
	 *            Name of difficulty.
	 * @return Game difficulty matching string.
	 */
	public static Difficulty getDifficulty(String diffStr) {
		// Beginner.
		if (diffStr.equals(Difficulty.BEGINNER.name)) {
			return Difficulty.BEGINNER;
		}
		// Standard.
		if (diffStr.equals(Difficulty.STANDARD.name)) {
			return Difficulty.STANDARD;
		}
		// Tournament
		if (diffStr.equals(Difficulty.TOURNAMENT.name)) {
			return Difficulty.TOURNAMENT;
		}
		// No difficulty defined.
		return null;
	}

	/**
	 * Returns a reference to the game's map object.
	 * 
	 * @return Reference to game map.
	 */
	public Map getMap() {
		return this.map;
	}

	/**
	 * Returns the game's difficulty.
	 * 
	 * @return The game's difficulty.
	 */
	public Difficulty getDifficulty() {
		return this.difficulty;
	}

	/**
	 * Returns the game's number of players.
	 * 
	 * @return Number of players in game.
	 */
	public int getNumPlayers() {
		return this.numPlayers;
	}

	/**
	 * Adds the given player to the game.
	 * 
	 * @param player
	 *            Player to add to game.
	 * @throws Exception
	 */
	public void addPlayer(Player player) throws Exception {
		if (players.size() < MAX_NUM_PLAYERS) {
			players.add(player);
		} else {
			throw new Exception("The game's player list is full.");
		}
	}

	/**
	 * Returns all players in the game.
	 * 
	 * @return List of players in game.
	 */
	public ArrayList<Player> getPlayers() {
		return players;
	}

	/**
	 * Returns the number of rounds for this game.
	 * 
	 * @return
	 */
	public int getNumRounds() {
		return numRounds;
	}
}